package service

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"sysu-giep/internal/database/models"
	"sysu-giep/pkg/logger"

	"go.uber.org/zap"
	"gorm.io/gorm"
)

// PrivateChatService 私聊服务
type PrivateChatService struct {
	db *gorm.DB
}

// NewPrivateChatService 创建私聊服务
func NewPrivateChatService(db *gorm.DB) *PrivateChatService {
	return &PrivateChatService{
		db: db,
	}
}

// GetUserChats 获取用户的私聊会话列表
func (s *PrivateChatService) GetUserChats(userID uint, page, size int) ([]models.PrivateChat, int64, error) {
	var chats []models.PrivateChat
	var total int64

	// 构建查询 - 获取用户参与的所有私聊会话
	query := s.db.Model(&models.PrivateChat{}).
		Where("(user1_id = ? OR user2_id = ?) AND is_active = ?", userID, userID, true)

	// 获取总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, fmt.Errorf("获取私聊会话总数失败: %v", err)
	}

	// 分页查询
	offset := (page - 1) * size
	if err := query.
		Preload("User1").
		Preload("User2").
		Order("last_message_at DESC, updated_at DESC").
		Offset(offset).
		Limit(size).
		Find(&chats).Error; err != nil {
		return nil, 0, fmt.Errorf("获取私聊会话列表失败: %v", err)
	}

	return chats, total, nil
}

// GetOrCreateChat 获取或创建私聊会话
func (s *PrivateChatService) GetOrCreateChat(user1ID, user2ID uint) (*models.PrivateChat, error) {
	// 检查两个用户是否可以私聊
	var user1, user2 models.User
	if err := s.db.First(&user1, user1ID).Error; err != nil {
		return nil, errors.New("用户1不存在")
	}
	if err := s.db.First(&user2, user2ID).Error; err != nil {
		return nil, errors.New("用户2不存在")
	}

	if !models.CanChat(&user1, &user2) {
		return nil, errors.New("这两个用户之间不能私聊")
	}

	// 查找现有会话
	var chat models.PrivateChat
	err := s.db.Where("((user1_id = ? AND user2_id = ?) OR (user1_id = ? AND user2_id = ?)) AND is_active = ?",
		user1ID, user2ID, user2ID, user1ID, true).
		Preload("User1").
		Preload("User2").
		First(&chat).Error

	if err == nil {
		// 会话已存在
		return &chat, nil
	}

	if !errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, fmt.Errorf("查询私聊会话失败: %v", err)
	}

	// 创建新会话
	chat = models.PrivateChat{
		User1ID:  user1ID,
		User2ID:  user2ID,
		IsActive: true,
	}

	if err := s.db.Create(&chat).Error; err != nil {
		// 如果是唯一约束冲突，说明会话已存在，重新查询
		if strings.Contains(err.Error(), "Duplicate entry") || strings.Contains(err.Error(), "UNIQUE constraint failed") {
			err = s.db.Where("((user1_id = ? AND user2_id = ?) OR (user1_id = ? AND user2_id = ?)) AND is_active = ?",
				user1ID, user2ID, user2ID, user1ID, true).
				Preload("User1").
				Preload("User2").
				First(&chat).Error
			if err != nil {
				return nil, fmt.Errorf("查询私聊会话失败: %v", err)
			}
			return &chat, nil
		}
		return nil, fmt.Errorf("创建私聊会话失败: %v", err)
	}

	// 预加载关联数据
	if err := s.db.Preload("User1").Preload("User2").First(&chat, chat.ID).Error; err != nil {
		logger.Error(fmt.Errorf("预加载私聊会话数据失败: %w", err))
	}

	return &chat, nil
}

// GetChatMessages 获取私聊消息
func (s *PrivateChatService) GetChatMessages(
	user1ID, user2ID uint,
	page, size int,
	beforeTime, afterTime *time.Time,
) ([]models.PrivateMessage, int64, error) {
	// 查找私聊会话
	var chat models.PrivateChat
	err := s.db.Where("((user1_id = ? AND user2_id = ?) OR (user1_id = ? AND user2_id = ?)) AND is_active = ?",
		user1ID, user2ID, user2ID, user1ID, true).
		First(&chat).Error

	if err != nil {
		return nil, 0, errors.New("私聊会话不存在")
	}

	var messages []models.PrivateMessage
	var total int64

	// 构建查询
	query := s.db.Model(&models.PrivateMessage{}).Where("private_chat_id = ?", chat.ID)

	// 添加时间筛选
	if beforeTime != nil {
		query = query.Where("sent_at < ?", *beforeTime)
	}
	if afterTime != nil {
		query = query.Where("sent_at > ?", *afterTime)
	}

	// 获取总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, fmt.Errorf("获取消息总数失败: %v", err)
	}

	// 分页查询
	offset := (page - 1) * size
	if err := query.
		Preload("Sender").
		Preload("ReplyTo").
		Order("sent_at DESC").
		Offset(offset).
		Limit(size).
		Find(&messages).Error; err != nil {
		return nil, 0, fmt.Errorf("获取私聊消息失败: %v", err)
	}

	return messages, total, nil
}

// SendMessage 发送私聊消息
func (s *PrivateChatService) SendMessage(
	senderID, receiverID uint,
	content string,
	messageType models.MessageType,
	replyToID *uint,
	fileURL, fileName string,
	fileSize *int64,
) (*models.PrivateMessage, error) {
	// 获取或创建私聊会话
	chat, err := s.GetOrCreateChat(senderID, receiverID)
	if err != nil {
		return nil, err
	}

	// 验证回复消息是否存在（如果指定了回复）
	if replyToID != nil {
		var replyMessage models.PrivateMessage
		if err := s.db.Where("id = ? AND private_chat_id = ?", *replyToID, chat.ID).First(&replyMessage).Error; err != nil {
			return nil, errors.New("回复的消息不存在")
		}
	}

	// 开始事务
	tx := s.db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 创建消息
	message := &models.PrivateMessage{
		PrivateChatID: chat.ID,
		SenderID:      senderID,
		ReplyToID:     replyToID,
		Type:          messageType,
		Content:       content,
		Status:        models.MessageStatusSent,
		FileURL:       fileURL,
		FileName:      fileName,
		SentAt:        time.Now(),
	}

	// 处理FileSize字段
	message.FileSize = fileSize

	if err := tx.Create(message).Error; err != nil {
		tx.Rollback()
		return nil, fmt.Errorf("发送消息失败: %v", err)
	}

	// 更新会话的最后消息时间
	if err := tx.Model(chat).Update("last_message_at", time.Now()).Error; err != nil {
		tx.Rollback()
		return nil, fmt.Errorf("更新会话时间失败: %v", err)
	}

	// 提交事务
	if err := tx.Commit().Error; err != nil {
		return nil, fmt.Errorf("提交事务失败: %v", err)
	}

	// 预加载关联数据
	if err := s.db.Preload("Sender").Preload("ReplyTo").First(message, message.ID).Error; err != nil {
		logger.Error(fmt.Errorf("预加载消息数据失败: %w", err))
	}

	logger.Info("发送私聊消息成功",
		zap.Uint("message_id", message.ID),
		zap.Uint("private_chat_id", chat.ID),
		zap.Uint("sender_id", senderID),
		zap.Uint("receiver_id", receiverID),
		zap.String("type", string(messageType)),
	)

	return message, nil
}

// MarkMessagesAsRead 标记消息为已读
func (s *PrivateChatService) MarkMessagesAsRead(userID, partnerID uint) error {
	// 查找私聊会话
	var chat models.PrivateChat
	err := s.db.Where("((user1_id = ? AND user2_id = ?) OR (user1_id = ? AND user2_id = ?)) AND is_active = ?",
		userID, partnerID, partnerID, userID, true).
		First(&chat).Error

	if err != nil {
		return errors.New("私聊会话不存在")
	}

	// 标记该会话中用户未读的消息为已读
	now := time.Now()
	if err := s.db.Model(&models.PrivateMessage{}).
		Where("private_chat_id = ? AND sender_id != ? AND read_at IS NULL",
			chat.ID, userID).
		Update("read_at", now).Error; err != nil {
		return fmt.Errorf("标记消息为已读失败: %v", err)
	}

	return nil
}

// GetUnreadMessageCount 获取用户的总未读消息数量
func (s *PrivateChatService) GetUnreadMessageCount(userID uint) (int64, error) {
	var count int64

	// 获取用户参与的所有私聊会话
	var chatIDs []uint
	if err := s.db.Model(&models.PrivateChat{}).
		Where("(user1_id = ? OR user2_id = ?) AND is_active = ?", userID, userID, true).
		Pluck("id", &chatIDs).Error; err != nil {
		return 0, fmt.Errorf("获取用户私聊会话失败: %v", err)
	}

	if len(chatIDs) == 0 {
		return 0, nil
	}

	// 计算未读消息数量
	if err := s.db.Model(&models.PrivateMessage{}).
		Where("private_chat_id IN ? AND sender_id != ? AND read_at IS NULL", chatIDs, userID).
		Count(&count).Error; err != nil {
		return 0, fmt.Errorf("计算未读消息数量失败: %v", err)
	}

	return count, nil
}

// GetChatUnreadCount 获取与特定用户的未读消息数量
func (s *PrivateChatService) GetChatUnreadCount(userID, partnerID uint) (int64, error) {
	// 查找私聊会话
	var chat models.PrivateChat
	err := s.db.Where("((user1_id = ? AND user2_id = ?) OR (user1_id = ? AND user2_id = ?)) AND is_active = ?",
		userID, partnerID, partnerID, userID, true).
		First(&chat).Error

	if err != nil {
		return 0, errors.New("私聊会话不存在")
	}

	var count int64
	if err := s.db.Model(&models.PrivateMessage{}).
		Where("private_chat_id = ? AND sender_id != ? AND read_at IS NULL", chat.ID, userID).
		Count(&count).Error; err != nil {
		return 0, fmt.Errorf("计算未读消息数量失败: %v", err)
	}

	return count, nil
}

// DeleteChat 删除私聊会话
func (s *PrivateChatService) DeleteChat(userID, partnerID uint) error {
	// 查找私聊会话
	var chat models.PrivateChat
	err := s.db.Where("((user1_id = ? AND user2_id = ?) OR (user1_id = ? AND user2_id = ?)) AND is_active = ?",
		userID, partnerID, partnerID, userID, true).
		First(&chat).Error

	if err != nil {
		return errors.New("私聊会话不存在")
	}

	// 软删除会话
	if err := s.db.Model(&chat).Update("is_active", false).Error; err != nil {
		return fmt.Errorf("删除私聊会话失败: %v", err)
	}

	return nil
}

// GetChatPartners 获取用户的聊天对象列表
func (s *PrivateChatService) GetChatPartners(userID uint) ([]models.User, error) {
	var partners []models.User

	// 查询与用户有私聊会话的其他用户
	subQuery := s.db.Model(&models.PrivateChat{}).
		Select("CASE WHEN user1_id = ? THEN user2_id ELSE user1_id END", userID).
		Where("(user1_id = ? OR user2_id = ?) AND is_active = ?", userID, userID, true)

	if err := s.db.Where("id IN (?)", subQuery).Find(&partners).Error; err != nil {
		return nil, fmt.Errorf("获取聊天对象列表失败: %v", err)
	}

	return partners, nil
}

// SearchUsers 搜索用户（用于聊天）
func (s *PrivateChatService) SearchUsers(keyword string, currentUserID uint) ([]models.User, error) {
	var users []models.User

	// 搜索用户名或真实姓名包含关键词的用户
	// 只返回可以与当前用户聊天的用户
	query := s.db.Model(&models.User{}).
		Where("(username LIKE ? OR real_name LIKE ?) AND id != ? AND status = ?",
			"%"+keyword+"%", "%"+keyword+"%", currentUserID, models.StatusApproved)

	if err := query.Find(&users).Error; err != nil {
		return nil, fmt.Errorf("搜索用户失败: %v", err)
	}

	// 过滤出可以与当前用户聊天的用户
	var chatableUsers []models.User
	var currentUser models.User
	if err := s.db.First(&currentUser, currentUserID).Error; err != nil {
		return nil, fmt.Errorf("获取当前用户信息失败: %v", err)
	}

	for _, user := range users {
		if models.CanChat(&currentUser, &user) {
			chatableUsers = append(chatableUsers, user)
		}
	}

	return chatableUsers, nil
}

// GetOnlineUsers 获取在线用户列表（简化版本，实际应该基于WebSocket连接状态）
func (s *PrivateChatService) GetOnlineUsers(currentUserID uint) ([]models.User, error) {
	var users []models.User

	// 获取可以与当前用户聊天的用户
	var currentUser models.User
	if err := s.db.First(&currentUser, currentUserID).Error; err != nil {
		return nil, fmt.Errorf("获取当前用户信息失败: %v", err)
	}

	// 查询所有已通过审核的用户
	if err := s.db.Where("status = ? AND id != ?", models.StatusApproved, currentUserID).Find(&users).Error; err != nil {
		return nil, fmt.Errorf("获取用户列表失败: %v", err)
	}

	// 过滤出可以与当前用户聊天的用户
	var chatableUsers []models.User
	for _, user := range users {
		if models.CanChat(&currentUser, &user) {
			// 注意：这里简化处理，实际应该检查WebSocket连接状态
			// 由于User模型没有Online字段，我们暂时不设置在线状态
			chatableUsers = append(chatableUsers, user)
		}
	}

	return chatableUsers, nil
}
